"""
test.py - 装饰器

装饰器：用一个函数去装饰另一个函数或类，为其提供额外的能力，实现了一种名为代理模式的经典设计模式。
横切关注功能（cross-concern）：跟正常的业务没有必然联系的功能，这样的功能最适合用装饰器（代理模式）来实现。

作业：写一个装饰器，如果函数返回了字符串，就将字符串每个单词首字母大写。
预习：带参数的装饰器（装饰器本身也可以参数化）---> 尝试将刚才的装饰器记录时间的功能放到数据库或文件

Author: Hao
Date: 2021/9/8
"""
import random
import time
from functools import wraps


def titlize_string(func):

    @wraps(func)
    def wrapper(*args, **kwargs):
        ret_value = func(*args, **kwargs)
        if isinstance(ret_value, str):
            ret_value = ret_value.title()
        return ret_value

    return wrapper


@titlize_string
def say_hello():
    return 'hello, world'


@titlize_string
def get_random_num():
    return random.randrange(100)


# 对装饰器进行参数化（通过传入一个output函数，将wrapper函数跟print解耦合）
def log_time(output):

    # 装饰器函数的参数是被装饰的函数，它返回的是带有装饰功能的函数
    def decorate(func):

        @wraps(func)
        def wrapper(*args, **kwargs):
            start = time.time()
            ret_value = func(*args, **kwargs)
            end = time.time()
            output(func.__name__, end - start)
            return ret_value

        return wrapper

    return decorate


def output_to_console(fname, duration):
    print(f'{fname}函数执行时间: {duration:.3f}秒')


def output_to_file(fname, duration):
    with open('access.log', 'a') as file:
        file.write(f'{fname}函数: {duration:.3f}秒\r\n')


def output_to_db(fname, duration):
    # Todo: 将函数的名字和执行时间写入二维表
    pass


# download = log_time(print)(download)
# @log_time(output_to_console)
@log_time(output_to_file)
def download(filename):
    print(f'开始下载 {filename}.')
    time.sleep(random.randrange(2, 5))
    print(f'{filename} 下载完成.')


@log_time(output_to_file)
def upload(filename):
    print(f'开始上传 {filename}.')
    time.sleep(random.randrange(3, 5))
    print(f'{filename} 上传完成.')


if __name__ == '__main__':
    # print(say_hello())
    # print(say_hello.__wrapped__())
    # print(get_random_num())
    # download = log_time(print)(download)
    download('Python从入门到住院.pdf')
    upload('MySQL从删库到跑路.avi')
    #
    # # 取消装饰器（得到被装饰之前的原函数）
    # download.__wrapped__('Linux从精通到放弃.pdf')
